import gradio as gr
import os
import json
import uvicorn
from fastapi import FastAPI, HTTPException, UploadFile, File
from pydantic import BaseModel
from typing import Optional, List
import base64
from openai import OpenAI
from io import BytesIO

# --- 配置部分 ---
# 从环境变量或直接设置您的百度AI API Key
BAIDU_API_KEY = os.environ.get("BAIDU_API_KEY", "xxx")  # 替换为您的实际API Key
BAIDU_BASE_URL = "https://aistudio.baidu.com/llm/lmapi/v3"
MODEL_NAME = "ernie-4.5-turbo-vl"  # 百度多模态模型

# 初始化OpenAI客户端以兼容百度API
client = OpenAI(
    api_key=BAIDU_API_KEY,
    base_url=BAIDU_BASE_URL,
)


# --- 核心处理函数 ---
def generate_analysis_core(sport_type, user_level, description="", image_data=None):
    """
    根据用户输入生成运动分析的核心逻辑
    """
    try:
        # 构建消息列表 - 确保所有消息内容格式统一为列表形式
        messages = [
            {
                "role": "system",
                "content": [
                    {
                        "type": "text",
                        "text": "你是一位专业的运动教练和运动医学专家，擅长分析各种运动的姿势正确性和技术动作。请根据用户提供的信息和图片/视频，提供专业、详细且实用的运动指导建议。",
                    }
                ],
            }
        ]

        # 构建用户消息内容
        user_text = f"""
        运动类型: {sport_type}
        运动水平: {user_level}
        描述: {description if description else '无特殊描述'}
        """

        # 初始化用户消息内容列表
        user_content = [{"type": "text", "text": user_text}]

        # 如果有图片数据，添加图片内容
        if image_data:
            user_content.append({"type": "image_url", "image_url": {"url": image_data}})

        # 添加用户消息到消息列表
        messages.append({"role": "user", "content": user_content})

        # 调用百度AI API
        completion = client.chat.completions.create(
            model=MODEL_NAME,
            messages=messages,
            stream=False,
            temperature=0.6,
        )

        ai_response = completion.choices[0].message.content
        return {"success": True, "result": ai_response}
    except Exception as e:
        print(f"调用AI API时出错: {e}")
        return {"success": False, "error": f"分析失败：{str(e)}"}


# --- 核心处理函数 ---
def analyze_exercise_form_core(image_data=None, video_data=None, exercise_type=""):
    """
    分析运动姿势的核心函数
    """
    try:
        messages = [
            {
                "role": "system",
                "content": [
                    {
                        "type": "text",
                        "text": "你是一位专业的运动教练和物理治疗师，擅长分析各种运动姿势的正确性，并提供专业的改进建议。你的分析应该科学、准确且易于理解。",
                    }
                ],
            }
        ]

        user_content = []

        # 添加文本描述
        if exercise_type:
            user_content.append(
                {
                    "type": "text",
                    "text": f"请分析这个{exercise_type}动作的姿势是否正确，指出可能存在的问题，并提供详细的改进建议。请包括：1. 姿势评估；2. 主要问题；3. 改进方法；4. 注意事项。",
                }
            )

        # 处理图片
        if image_data:
            # 转换为base64格式的URL
            base64_image = base64.b64encode(image_data).decode("utf-8")
            user_content.append(
                {
                    "type": "image_url",
                    "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"},
                }
            )

        # 目前视频处理简化为处理单帧，实际应用中可以处理多帧
        if video_data:
            # 这里简化处理，实际应用中可以提取视频关键帧进行分析
            user_content.append(
                {
                    "type": "text",
                    "text": "这是一个运动视频，主要分析动作的规范性和可能的受伤风险。",
                }
            )

        messages.append({"role": "user", "content": user_content})

        # 调用百度AI API
        completion = client.chat.completions.create(
            model=MODEL_NAME,
            messages=messages,
            stream=False,
            temperature=0.6,
        )

        ai_response = completion.choices[0].message.content
        return {"success": True, "result": ai_response}
    except Exception as e:
        print(f"调用AI API时出错: {e}")
        return {"success": False, "error": f"分析失败：{str(e)}"}


def generate_workout_plan_core(
    fitness_level,
    goals,
    available_days,
    duration_per_day,
    equipment_available,
    injuries_or_limitations="",
):
    """
    生成个性化训练计划的核心函数
    """
    try:
        # 构建发送给AI的指令
        prompt = f"""
你是一位专业的健身教练和运动规划专家。请根据以下信息，为用户生成一份科学、有效的个性化训练计划：

用户信息：
- 健身水平: {fitness_level}
- 健身目标: {goals}
- 每周可训练天数: {available_days}天
- 每天训练时长: {duration_per_day}分钟
- 可用器材: {equipment_available if equipment_available else '无特殊器材'}
- 伤病或限制: {injuries_or_limitations if injuries_or_limitations else '无'}

请生成一份详细的训练计划，包含以下内容：

1. 总体训练策略：根据用户目标和条件制定的训练原则
2. 每周训练安排：详细列出每天的训练重点和主要内容
3. 具体动作指导：每个训练日包含的具体动作，每个动作的组数、次数和注意事项
4. 进阶建议：如何随着体能提升调整训练计划
5. 营养与恢复建议：简单的饮食和恢复建议

请确保计划科学合理，符合运动生理学原理，并且切实可行。
"""

        # 调用百度AI API
        completion = client.chat.completions.create(
            model=MODEL_NAME,
            messages=[
                {
                    "role": "system",
                    "content": [
                        {
                            "type": "text",
                            "text": "你是一位专业的健身教练，擅长制定科学有效的训练计划。",
                        }
                    ],
                },
                {"role": "user", "content": [{"type": "text", "text": prompt}]},
            ],
            stream=False,
            temperature=0.7,
        )

        ai_response = completion.choices[0].message.content
        return {"success": True, "result": ai_response}
    except Exception as e:
        print(f"调用AI API时出错: {e}")
        return {"success": False, "error": f"生成计划失败：{str(e)}"}


def get_exercise_knowledge_core(topic, question=""):
    """
    获取运动知识的核心函数
    """
    try:
        # 构建发送给AI的指令
        if question:
            prompt = f"关于{topic}，我的问题是：{question}。请给出专业、详细且易懂的解答，最好能包括实际应用的建议。"
        else:
            prompt = f"请提供关于{topic}的专业知识，包括定义、重要性、正确方法和常见误区。内容要详实且实用。"

        # 调用百度AI API
        completion = client.chat.completions.create(
            model=MODEL_NAME,
            messages=[
                {
                    "role": "system",
                    "content": [
                        {
                            "type": "text",
                            "text": "你是运动科学和健身领域的专家，能够提供准确、科学的运动知识。",
                        }
                    ],
                },
                {"role": "user", "content": [{"type": "text", "text": prompt}]},
            ],
            stream=False,
            temperature=0.6,
        )

        ai_response = completion.choices[0].message.content
        return {"success": True, "result": ai_response}
    except Exception as e:
        print(f"调用AI API时出错: {e}")
        return {"success": False, "error": f"获取知识失败：{str(e)}"}


# --- Gradio界面包装函数 ---
def analyze_exercise_form_for_gradio(image, video, exercise_type):
    """用于Gradio界面的运动姿势分析函数"""
    image_data = None
    if image is not None:
        # 转换为字节数据
        buf = BytesIO()
        image.save(buf, format="JPEG")
        image_data = buf.getvalue()

    video_data = None
    if video is not None:
        # 简单处理，实际应用中可以处理视频文件
        video_data = b"video_data_placeholder"

    result_dict = analyze_exercise_form_core(image_data, video_data, exercise_type)
    if result_dict["success"]:
        return result_dict["result"]
    else:
        return f"抱歉，分析运动姿势时遇到了问题：{result_dict['error']}"


def generate_workout_plan_for_gradio(
    fitness_level,
    goals,
    available_days,
    duration_per_day,
    equipment_available,
    injuries_or_limitations,
):
    """用于Gradio界面的训练计划生成函数"""
    result_dict = generate_workout_plan_core(
        fitness_level,
        goals,
        available_days,
        duration_per_day,
        equipment_available,
        injuries_or_limitations,
    )
    if result_dict["success"]:
        return result_dict["result"]
    else:
        return f"抱歉，生成训练计划时遇到了问题：{result_dict['error']}"


def get_exercise_knowledge_for_gradio(topic, question):
    """用于Gradio界面的运动知识获取函数"""
    result_dict = get_exercise_knowledge_core(topic, question)
    if result_dict["success"]:
        return result_dict["result"]
    else:
        return f"抱歉，获取运动知识时遇到了问题：{result_dict['error']}"


# --- Gradio界面包装函数 ---
def generate_analysis_for_gradio(sport_type, user_level, description, image):
    """包装函数，供Gradio界面调用"""
    # 处理图片（如果有）
    image_data = None
    if image is not None:
        # 将图片转换为base64格式
        buf = BytesIO()
        image.save(buf, format="JPEG")
        base64_image = base64.b64encode(buf.getvalue()).decode("utf-8")
        image_data = f"data:image/jpeg;base64,{base64_image}"

    result_dict = generate_analysis_core(
        sport_type, user_level, description, image_data
    )
    if result_dict["success"]:
        return result_dict["result"]
    else:
        return f"抱歉，生成分析时遇到了问题：{result_dict['error']}"


# --- Gradio界面定义 ---
def gradio_interface():
    with gr.Blocks(title="动智 - 智能运动分析助手") as demo:
        gr.Markdown("## 🚀 动智 - 智能运动分析助手 ")
        gr.Markdown(
            "利用AI技术提供专业运动指导，助您科学锻炼，避免受伤，高效达成健身目标。"
        )

        with gr.Tabs():
            with gr.Tab("运动姿势分析"):
                gr.Markdown(
                    "上传运动图片或视频，AI将分析您的动作姿势并提供专业改进建议。"
                )

                with gr.Row():
                    with gr.Column(scale=1):
                        sport_type = gr.Dropdown(
                            label="运动类型",
                            choices=[
                                "跑步",
                                "游泳",
                                "举重",
                                "瑜伽",
                                "篮球",
                                "足球",
                                "网球",
                                "羽毛球",
                                "健身",
                                "其他",
                            ],
                            value="健身",
                        )
                        user_level = gr.Radio(
                            label="运动水平",
                            choices=["初学者", "中级", "高级", "专业"],
                            value="初学者",
                        )

                        description = gr.Textbox(  # 修复了这里的缩进错误
                            label="运动情况描述 (可选)",
                            placeholder="请描述您遇到的问题或想要改进的方面...",
                        )

                        image = gr.Image(
                            label="上传运动图片",
                            type="pil",  # 改为PIL格式以便处理
                            height=300,
                        )
                        analyze_btn = gr.Button("分析姿势", variant="primary")

                    with gr.Column(scale=1):
                        analysis_output = gr.Markdown(label="姿势分析结果")

                # 修复变量引用错误，将output改为analysis_output
                analyze_btn.click(
                    fn=generate_analysis_for_gradio,
                    inputs=[sport_type, user_level, description, image],
                    outputs=analysis_output,
                )

            with gr.Tab("个性化训练计划"):
                gr.Markdown("输入您的健身信息，获取量身定制的科学训练计划。")

                with gr.Row():
                    with gr.Column(scale=1):
                        fitness_level = gr.Radio(
                            label="健身水平",
                            choices=["初学者", "中级", "高级"],
                            value="初学者",
                        )
                        goals = gr.CheckboxGroup(
                            label="健身目标",
                            choices=[
                                "增肌",
                                "减脂",
                                "提高耐力",
                                "增强灵活性",
                                "改善体态",
                                "提升运动表现",
                            ],
                            value=["增肌", "减脂"],
                        )
                        available_days = gr.Slider(
                            label="每周可训练天数",
                            minimum=1,
                            maximum=7,
                            value=3,
                            step=1,
                            interactive=True,
                        )
                        duration_per_day = gr.Slider(
                            label="每次训练时长 (分钟)",
                            minimum=10,
                            maximum=120,
                            value=45,
                            step=5,
                            interactive=True,
                        )
                        equipment_available = gr.Textbox(
                            label="可用器材 (可选)",
                            placeholder="例如：哑铃、杠铃、跑步机等，无器材可留空",
                        )
                        injuries_or_limitations = gr.Textbox(
                            label="伤病或身体限制 (可选)",
                            placeholder="例如：膝盖不适、腰部旧伤等，无则留空",
                        )
                        plan_btn = gr.Button("生成训练计划", variant="primary")

                    with gr.Column(scale=1):
                        plan_output = gr.Markdown(label="个性化训练计划")

                plan_btn.click(
                    fn=generate_workout_plan_for_gradio,
                    inputs=[
                        fitness_level,
                        goals,
                        available_days,
                        duration_per_day,
                        equipment_available,
                        injuries_or_limitations,
                    ],
                    outputs=plan_output,
                )

            with gr.Tab("运动知识库"):
                gr.Markdown("查询各类运动知识，解答您的健身疑问。")

                with gr.Row():
                    with gr.Column(scale=1):
                        knowledge_topic = gr.Dropdown(
                            label="知识主题",
                            choices=[
                                "肌肉训练",
                                "有氧运动",
                                "拉伸放松",
                                "营养补充",
                                "损伤预防",
                                "恢复技巧",
                                "运动心理学",
                                "其他",
                            ],
                            value="损伤预防",
                        )
                        knowledge_question = gr.Textbox(
                            label="具体问题 (可选)",
                            placeholder="请输入您想了解的具体问题",
                        )
                        knowledge_btn = gr.Button("获取知识", variant="primary")

                    with gr.Column(scale=1):
                        knowledge_output = gr.Markdown(label="运动知识解答")

                knowledge_btn.click(
                    fn=get_exercise_knowledge_for_gradio,
                    inputs=[knowledge_topic, knowledge_question],
                    outputs=knowledge_output,
                )

        gr.Markdown(
            """
        ---
        ### 使用提示
        - 运动姿势分析：尽量上传清晰、正面或侧面的动作图片/视频，效果更佳
        - 训练计划：请如实填写您的身体状况和限制，以获得更安全有效的计划
        - 所有AI建议仅供参考，如有严重健康问题，请先咨询专业医师
        
        ### API接口
        本应用提供API接口供集成：
        - 姿势分析: POST /api/analyze
        - 训练计划: POST /api/plan
        - 运动知识: POST /api/knowledge
        """
        )

    return demo


# --- FastAPI应用和API端点定义 ---
app = FastAPI(
    title="动智 - 智能运动分析助手API",
    description="提供运动分析和指导的AI服务",
)


# 请求模型定义
class AnalysisRequest(BaseModel):
    sport_type: str
    user_level: str
    description: Optional[str] = ""
    image_data: Optional[str] = None


class PlanRequest(BaseModel):
    fitness_level: str
    goals: List[str]
    available_days: int
    duration_per_day: int
    equipment_available: Optional[str] = ""
    injuries_or_limitations: Optional[str] = ""


class KnowledgeRequest(BaseModel):
    topic: str
    question: Optional[str] = ""


# API端点
@app.post("/api/analyze", summary="生成运动分析")
async def api_generate_analysis(request: AnalysisRequest):
    result = generate_analysis_core(
        request.sport_type, request.user_level, request.description, request.image_data
    )
    if result["success"]:
        return result
    else:
        raise HTTPException(status_code=500, detail=result["error"])


@app.post("/api/plan", summary="生成训练计划")
async def api_generate_plan(request: PlanRequest):
    result = generate_workout_plan_core(
        request.fitness_level,
        ", ".join(request.goals),
        request.available_days,
        request.duration_per_day,
        request.equipment_available,
        request.injuries_or_limitations,
    )
    if result["success"]:
        return result
    else:
        raise HTTPException(status_code=500, detail=result["error"])


@app.post("/api/knowledge", summary="获取运动知识")
async def api_get_knowledge(request: KnowledgeRequest):
    result = get_exercise_knowledge_core(request.topic, request.question)
    if result["success"]:
        return result
    else:
        raise HTTPException(status_code=500, detail=result["error"])


@app.get("/health", summary="健康检查")
async def health_check():
    return {"status": "healthy", "service": "动智 - 智能运动分析助手"}


# 挂载Gradio界面到FastAPI应用
demo = gradio_interface()
app = gr.mount_gradio_app(app=app, blocks=demo, path="/")

if __name__ == "__main__":
    print("🚀 启动动智 - 智能运动分析助手...")
    print("📱 界面访问地址: http://localhost:7860")
    print("💻 API文档地址: http://localhost:7860/docs")
    print("-" * 50)
    uvicorn.run(app, host="0.0.0.0", port=7860)
